Programming Foundations (Python)

A practical, mental-model focused introduction to Python: syntax minimalism, data handling, control flow, functions, error handling, packaging, and idiomatic style โ€” with interactive building blocks.

๐Ÿง  Mental Models
๐Ÿ” Control Flow
๐Ÿ“ฆ Modules
๐Ÿงช Testing
โ™ป๏ธ Iteration
๐Ÿงฐ Standard Lib

1. Core Concepts

Python emphasizes readability + object model simplicity.

Dynamic Typing

Names point to objects; object carries type. Rebinding doesn't mutate existing objects.

bindingsobjects

Everything is an Object

Functions, classes, modules โ€” all have identities & attributes. Int immutability โ†’ arithmetic returns new objects.

object model

Indentation = Structure

Block scope defined purely via indentation; no braces. Mixed tabs/spaces = errors.

PEP8

Immutability vs Mutability

Immutable: int, str, tuple, frozenset. Mutable: list, dict, set. Mutation side-effects propagate references.

side-effects

Basic Program Anatomy

#!/usr/bin/env python3
"""Greet user with friendly message."""
import math

def circle_area(r: float) -> float:
    return math.pi * r * r

if __name__ == "__main__":
    r = 3
    print(f"Area: {circle_area(r):.2f}")

Execution Model

  • Module top-level runs on first import (creates module object).
  • __name__ == "__main__" gate prevents side-effect logic on import.
  • Bytecode compiled (.pyc) โ†’ executed by CPython VM.

Type Hints

  • Optional, aid tooling; no runtime enforcement by default.
  • Use from __future__ import annotations for forward refs.
  • Adopt gradually: public APIs first.

Virtual Environments

  • Isolate dependencies per project.
  • python -m venv .venv โ†’ activate, then pip install.
  • Pin versions in requirements.txt.

2. Functions & Modularity

Decompose for clarity; embrace pure logic where possible.

Function Signatures

  • Explicit parameters > implicit globals.
  • Default args evaluate once (beware mutable defaults).
  • Keyword-only args enforce clarity (def f(*, mode)).

Return Styles

  • Single exit path not mandatory; readability first.
  • Use tuples / dataclasses for multi-value semantics.
  • Prefer exceptions over sentinel returns.

Higher-Order

  • Functions passed to map, sorted(key=...).
  • Lambdas for concise one-liners; avoid complex inline logic.
  • Closures capture lexical scope.

Mutable Default Pitfall

def append_item(x, bucket=[]):
    bucket.append(x)
    return bucket

print(append_item(1))  # [1]
print(append_item(2))  # [1, 2] (surprise!)

# Correct
def append_item_safe(x, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(x)
    return bucket

3. Built-in Data Structures

Choose representation to optimize clarity + complexity.

List

Resizable array. Append amortized O(1). Slice copies; list comps > manual loops.

sequence

Tuple

Immutable fixed-size sequence. Hashable if elements hashable โ†’ safe dict key.

immutable

Dict

Hash map. O(1) average access. Keys must be hashable + stable.

mapping

Set

Unique membership. O(1) avg add/test. Great for dedupe and membership tests.

membership

Dataclass

Auto boilerplate (__init__, repr). Use for plain data containers.

models

Deque

O(1) append/pop both ends. Use instead of list for queue semantics.

collections

List Comprehension vs Loop

# Imperative
squares = []
for i in range(10):
    squares.append(i * i)

# Comprehension
squares = [i * i for i in range(10)]

# With condition
evens = [x for x in squares if x % 2 == 0]

4. Errors & Exceptions

Use exceptions for exceptional control โ€” not ordinary flow.

Raising

  • raise ValueError("invalid")
  • Chain root cause: raise NewError() from err
  • Fail fast with precise types.

Handling

  • Catch narrow exceptions.
  • Use finally for cleanup.
  • Avoid blanket except: (swallows bugs).

Assertions

  • Internal invariants only.
  • Disabled under -O optimization.
  • Not for user input validation.

Try / Except Template

try:
    risky()
except (IOError, ValueError) as e:
    logger.error("Failure: %s", e)
    raise
else:
    print("Success")
finally:
    cleanup()

5. Interactive Practice Lab

Client-side helpers simulate transformations (no real Python execution sandbox).

Comprehension Builder

(converted)

Dict From JSON (keys)

(keys)

Regex Test (Pseudo)

(matches)

6. Syntax Cheat Sheet

High-frequency forms.

Primitives

int("10")  # 10
float("3.14")
str(42)     # "42"
len(seq)
# Truthiness: 0, '', [], {}, None => False

Collections

lst = [1,2,3]
tpl = (1,2,3)
set_ = {1,2,3}
d = {"a":1, "b":2}
# Unpacking
x, y, *rest = lst

Flow

for i in range(5):
    ...
while cond:
    ...
if x > 0:
    ...
elif x == 0:
    ...
else:
    ...

Functions

def f(a, b=10, *args, **kw):
    return a + b

(lambda x: x+1)(2)

from dataclasses import dataclass
@dataclass
class User:
    name: str
    age: int

Error Tools

try:
    1/0
except ZeroDivisionError:
    ...

raise RuntimeError("fail")
assert cond, "msg"

Files

with open("data.txt") as f:
    data = f.read().splitlines()
Adopt formatting (Black) + linting (Ruff/Flake8) early; enforces consistency & reduces review noise.

7. Mastery Review

Track what you can explain, not just run.

Progress Checklist

Concept Q&A

Why are strings immutable?

Enables interning, hashing, safe sharing, and avoids unintended alias mutation; improves performance & security.

When use list vs tuple?

Tuple for fixed-size heterogeneous record semantics & hashable keys; list for dynamic sequence operations.

Why prefer comprehension over map/filter sometimes?

Improved readability and single-pass expression of intent; avoids lambda noise when simple transformations.

Difference between module and package?

Module = single .py file; package = directory with __init__.py (namespace). Packages enable structured imports & distribution.